package com.iffpx.opendoc.maven.plugin;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;

/**
 * Maven mojo to generate OpenAPI documentation document based on Swagger.
 * 
 * @author billi
 *
 */
@Mojo(name = "gen-swagger-doc", defaultPhase = LifecyclePhase.COMPILE,
    requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
public class OpendocSwaggerMojo extends AbstractMojo {

  /**
   * Location of the file.
   */
  @Parameter(defaultValue = "${project.build.directory}", property = "outputDir", required = true)
  private File outputDirectory;

  @Parameter(defaultValue = "${project}", readonly = true)
  private MavenProject project;

  @Component
  private MavenProjectHelper projectHelper;

  @Override
  public void execute() throws MojoExecutionException, MojoFailureException {
    // 60 spaces
    getLog().info("============================================================");
    getLog().info("Project Name: " + project.getName());
    getLog().info("project build output diectory: " + project.getBuild().getOutputDirectory());
    getLog().info("project build output diectory: " + outputDirectory);
    try {
      List<String> compiledClasses = project.getCompileClasspathElements();
      compiledClasses.forEach(compiledClass -> {
        getLog().info(compiledClass);
      });

      List<Dependency> dependencies = project.getDependencies();
      dependencies.forEach(dependency -> {
        getLog().info(dependency.getArtifactId());
      });
    } catch (DependencyResolutionRequiredException e) {
      e.printStackTrace();
    }

    ClassLoader defClassLoader = Thread.currentThread().getContextClassLoader();
    ClassLoader myClassLoader = createClassLoader(defClassLoader);
    Thread.currentThread().setContextClassLoader(myClassLoader);
  }

  private Collection<String> getDependentClasspathElements()
      throws DependencyResolutionRequiredException {
    Set<String> dependencies = new HashSet<String>();
    dependencies.add(project.getBuild().getOutputDirectory());
    List<String> compiledClasses = project.getCompileClasspathElements();
    List<String> runtimeClassPathes = project.getRuntimeClasspathElements();
    if (Objects.nonNull(compiledClasses)) {
      dependencies.addAll(compiledClasses);
    }
    if (Objects.nonNull(runtimeClassPathes)) {
      dependencies.addAll(runtimeClassPathes);
    }
    return dependencies;
  }

  private URLClassLoader createClassLoader(ClassLoader parent) {
    try {
      Collection<String> dependencies = getDependentClasspathElements();
      URL[] urls = new URL[dependencies.size()];
      int index = 0;
      for (String dependency : dependencies) {
        urls[index++] = Paths.get(dependency).toUri().toURL();
      }
      return new URLClassLoader(urls, parent);
    } catch (Exception e) {
      throw new RuntimeException("Dependency resolution (runtime + compile) is required");
    }
  }
}
